﻿/*
 * This file is part of CommunitySettlers.
 *
 * CommunitySettlers is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * CommunitySettlers is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with CommunitySettlers.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Author: Christoph Husse
 * 
 * Also checkout our homepage: http://communitysettlers.codeplex.com/
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using SettlersEngine.Exported;

namespace SettlersEngine
{
    internal class BuildingGrid : Grid
    {
        private Image[,] m_Images;
        public RuntimeMap Map { get; private set; }
        public IBuildableObject Building { get; private set; }
        public System.Drawing.Point CursorShift { get; private set; }
        public Exported.GameInstance Game { get { return Map.Game; } }

        public BuildingGrid(RuntimeMap inMap)
        {
            Map = inMap;
            m_Images = new Image[Map.ScreenWidth, Map.ScreenHeight];

            for (int x = Map.ScreenPosition.X, imgX = 0; x < Map.ScreenPosition.X + Map.ScreenWidth; x++, imgX++)
            {
                for (int y = Map.ScreenPosition.Y, imgY = 0; y < Map.ScreenPosition.Y + Map.ScreenHeight; y++, imgY++)
                {
                    Children.Add(m_Images[imgX, imgY] = new Image()
                    {
                        Margin = new Thickness(imgX * GameInstance.POSITION_SCALE, imgY * GameInstance.POSITION_SCALE, 0, 0),
                        VerticalAlignment = System.Windows.VerticalAlignment.Top,
                        HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
                        Width = 12,
                        Height = 12,
                        Source = new ImageSourceConverter().ConvertFromString("pack://application:,,,/SettlersEngine;component/Visual/Resources/LevelPoints/Level_00.png") as ImageSource,
                    });
                }
            }

            Visibility = System.Windows.Visibility.Hidden;

            Map.OnBuildSpaceChanged += Map_OnBuildSpaceChanged;
            Game.OnCursorChanged += Game_OnCursorChanged;
        }

        internal void RegisterMouseHandlers(FrameworkElement inElement)
        {
            inElement.MouseLeftButtonDown += BuildingGrid_MouseDown;
            inElement.MouseRightButtonUp += BuildingGrid_MouseUp;
        }

        internal void UnregisterMouseHandlers(FrameworkElement inElement)
        {
            inElement.MouseLeftButtonDown -= BuildingGrid_MouseDown;
            inElement.MouseRightButtonUp -= BuildingGrid_MouseUp;
        }

        void BuildingGrid_MouseUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            Hide();
        }

        void BuildingGrid_MouseDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            if (IsVisible)
            {
                IBuildableObject buildable = IBuildableObject.Create(BuildingType.Default,
                    Map, Building.Config.TypeIndex, CyclePoint.FromGrid(GetBuildingPosition()));

                Map.AddBuilding(buildable);
            }
        }

        void Map_OnBuildSpaceChanged(RuntimeMap inSender)
        {
            Update();
        }

        void Game_OnCursorChanged(GameInstance inSender, System.Drawing.Point inOldValue, System.Drawing.Point inNewValue)
        {
            if (Building != null)
            {
                Building building = (Building)Building.UserContext;
                System.Drawing.Point point = GetBuildingPosition();
                System.Drawing.Point cursor = Game.CursorPosition;


                if (m_Images[cursor.X, cursor.Y].Visibility == System.Windows.Visibility.Visible)
                {
                    building.Movable_OnPositionChanged(Building, CyclePoint.FromGrid(point), CyclePoint.FromGrid(point));
                    building.Visibility = System.Windows.Visibility.Visible;
                }
                else
                    building.Visibility = System.Windows.Visibility.Hidden;
            }
        }

        public System.Drawing.Point GetBuildingPosition()
        {
            return new System.Drawing.Point(
                Game.CursorPosition.X - CursorShift.X + Game.Map.ScreenPosition.X,
                Game.CursorPosition.Y - CursorShift.Y + Game.Map.ScreenPosition.Y);
        }


        public void Update()
        {
            if (Building == null)
                return;

            for (int x = Map.ScreenPosition.X, imgX = 0; x < Math.Min(Map.ScreenPosition.X + Map.ScreenWidth, Map.Width - 1); x++, imgX++)
            {
                for (int y = Map.ScreenPosition.Y, imgY = 0; y < Math.Min(Map.ScreenPosition.Y + Map.ScreenHeight, Map.Height - 1); y++, imgY++)
                {
                    if (Map.Grid.CanPlaceObject(Building, new System.Drawing.Point(x - CursorShift.X, y - CursorShift.Y)))
                        m_Images[imgX, imgY].Visibility = System.Windows.Visibility.Visible;
                    else
                        m_Images[imgX, imgY].Visibility = System.Windows.Visibility.Hidden;
                }
            }
        }

        public void Show(int inTypeIndex)
        {
            if (IsVisible)
                Hide();

            Building = Map.CreateBuildingPreview(inTypeIndex);
            CursorShift = new System.Drawing.Point(Building.VisualWidth / 2, Building.VisualHeight / 2);

            ((Building)Building.UserContext).Opacity = 0.5;

            Update();

            Visibility = System.Windows.Visibility.Visible;

            ((Building)Building.UserContext).Movable_OnPositionChanged(
                Building,
                CyclePoint.FromGrid(GetBuildingPosition()),
                CyclePoint.FromGrid(GetBuildingPosition()));
        }

        public void Hide()
        {
            if (Building != null)
                Building.Dispose();

            Building = null;

            Visibility = System.Windows.Visibility.Hidden;
        }
    }
}
